/********************************************
 * 功能说明: 
 * 模块名称: 
 * 系统名称: 
 * 软件版权: Frank
 * 系统版本: 1.0.0
 * 开发人员: Frank
 * 开发时间: 2019/12/12 11:17
 * 审核人员: 
 * 相关文档: 
 * 修改记录: 修改日期 修改人员 修改说明
 *********************************************/
package com.spring.arch.uaa.service;

import com.spring.arch.common.dto.result.ResultDTO;
import com.spring.arch.common.exception.ExceptionHolder;
import com.spring.arch.datasource.client.DatasourceClient;
import com.spring.arch.datasource.dto.DatasourceConfigDTO;
import com.spring.arch.uaa.enums.Constant;
import com.spring.arch.uaa.enums.OrganizationType;
import com.spring.arch.uaa.enums.ProjectStatus;
import com.spring.arch.uaa.errorcode.UaaErrorCode;
import com.spring.arch.uaa.model.Organization;
import com.spring.arch.uaa.model.Project;
import com.spring.arch.uaa.model.ProjectDatasource;
import com.spring.arch.common.dto.result.ResultDTO;
import com.spring.arch.common.exception.ExceptionHolder;
import com.spring.arch.datasource.client.DatasourceClient;
import com.spring.arch.datasource.dto.DatasourceConfigDTO;
import com.spring.arch.uaa.enums.Constant;
import com.spring.arch.uaa.enums.OrganizationType;
import com.spring.arch.uaa.enums.ProjectStatus;
import com.spring.arch.uaa.model.Organization;
import com.spring.arch.uaa.model.Project;
import com.spring.arch.uaa.model.ProjectDatasource;
import com.spring.arch.uaa.repository.ProjectDatasourceRepository;
import com.spring.arch.uaa.repository.ProjectRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;

import static com.spring.arch.uaa.errorcode.UaaErrorCode.E2001001001;
import static com.spring.arch.uaa.errorcode.UaaErrorCode.E2001007002;

/**
 * 项目服务层接口
 *
 * @author Frank
 * @version 1.0.0.1
 * @since 2019/12/12 11:17
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class ProjectService {

    @Autowired
    private ProjectRepository projectRepository;
    @Autowired
    private ProjectDatasourceRepository projectDatasourceRepository;
    @Autowired
    private OrganizationService organizationService;
    @Resource
    private DatasourceClient datasourceClient;

    public Project save(Project model) {
        //step0先跟根组织，创建数据源，再创建项目
        log.info("创建项目[{}], step0**先创建项目根组织[{}], 租户name为[{}]", model.getName(), model.getName(), model.getTenant().getName());
        Organization organization = new Organization();
        organization.setTenant(model.getTenant());
        organization.setParent(model.getRootOrganization());
        organization.setName(model.getName());
        organization.setType(OrganizationType.PROJECT);
        organization.setProject(null);
        organization.setCode(Constant.projectRootOrgCode(model.getCode()));
        organization = organizationService.save(organization);
        log.info("创建项目[{}], step0**先创建项目根组织[{}]完成, 租户name为[{}]", model.getName(), model.getName(), model.getTenant().getName());
        //step1 创建项目数据源
        log.info("创建项目[{}], step1**先创建数据源[{}], 租户name为[{}]", model.getName(), model.getCode(), model.getTenant().getName());
        ProjectDatasource projectDatasource = new ProjectDatasource();
        projectDatasource.setSchema(model.getCode());
        projectDatasource.setUsername(model.getCode());
        projectDatasource.setPassword(model.getCode());
        //临时存储
        projectDatasource.setUrl(model.getCode());
        projectDatasource = this.projectDatasourceRepository.save(projectDatasource);
        log.info("创建项目[{}], step1**创建数据源[{}], 租户name为[{}], 创建数据源成功", model.getName(), model.getCode(), model.getTenant().getName());
        //step2 设置项目对应的数据源配置信息
        log.info("创建项目[{}], step2**创建项目[{}], 租户name为[{}]", model.getName(), model.getName(), model.getTenant().getName());
        model.setDatasource(projectDatasource);
        //设置项目根组织
        model.setRootOrganization(organization);
        model.setStatus(ProjectStatus.ONLINE);
        Project project = projectRepository.save(model);
        organization.setProject(project);
        this.organizationService.save(organization);
        log.info("创建项目[{}], step2**创建项目[{}], 租户name为[{}], 创建项目成功", model.getName(), model.getName(), model.getTenant().getName());
        //step3 构建多实例数据源管理
        log.info("创建项目[{}], step3**创建数据源实例[{}], 租户name为[{}]", project.getName(), project.getName(), project.getTenant().getName());
        return project;
    }

    public void buildDatasource(Project project) {
        DatasourceConfigDTO datasourceConfigDTO = new DatasourceConfigDTO();
        datasourceConfigDTO.setProjectId(project.getId());
        datasourceConfigDTO.setSchemaName(project.getCode());
        datasourceConfigDTO.setPassword(project.getCode());
        datasourceConfigDTO.setUsername(project.getCode());
        ResultDTO<DatasourceConfigDTO> resultDTO = datasourceClient.enroll(datasourceConfigDTO);
        if (resultDTO.isFailure()) {
            log.info("创建项目[{}], step3**创建数据源实例[{}], 租户name为[{}], 创建数据源实例异常", project.getName(), project.getName(), project.getTenant().getName());
            throw ExceptionHolder.serviceException(UaaErrorCode.E2001007002, project.getName(), project.getCode());
        }
        log.info("创建项目[{}], step3**创建数据源实例[{}], 租户name为[{}]，创建数据源实例成功", project.getName(), project.getName(), project.getTenant().getName());

    }

    public void delete(UUID id) {
        final Project project = projectRepository.findById(id)
                .orElseThrow(() -> ExceptionHolder.serviceException(UaaErrorCode.E2001001001, "租户"));
        project.setDisable(true);
        //标记项目不可用
        projectRepository.save(project);
        // 将项目数据源下线
        datasourceClient.offline(id);
    }

    public Project update(Project model) {
        return this.projectRepository.save(model);
    }
}
